import cv2 as cv
import numpy as np
import copy
filename = r'D:\photo\rice.jpg'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
'''.cv2.THRESH_BINARY   表示阈值的二值化操作，大于阈值使用maxval表示，小于阈值使用0表示'''
OTSU = cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,13,1)
kernel = np.ones((5,5))
'''形态学开运算去噪'''
opening = cv.morphologyEx(OTSU,cv.MORPH_OPEN,kernel)
'''对得到的结果进行拷贝'''
seg = copy.deepcopy(opening)
'''第一个是输入图像，第二个是
轮廓检索模式，第三个是轮廓近似方法。返回值有三个，第一个是图像，第二个
是轮廓，第三个是（轮廓的）层析结构。轮廓（第二个返回值）是一个 Python
列表，其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组，包
含对象边界点（x，y）的坐标。opencv4返回两个值'''
contours,hierarchy = cv.findContours(seg,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
count = 0
area_array = np.array([])
line_array = np.array([])
perimeter_array = np.array([])
for i in range(1,len(contours),1):
    c = contours[i]
    ret = cv.minAreaRect(c)
    perimeter = cv.arcLength(c,True)
    '''得到矩形的四个角点'''
    x, y, w, h = cv.boxPoints(ret)
    l1 = ((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2) ** 0.5
    l2 = ((x[0] - h[0]) ** 2 + (x[1] - h[1]) ** 2) ** 0.5
    '''计算面积'''
    miniarea = l1*l2
    if l1 > l2:
        line = l1
    else:
        line = l2
    line_array = np.append(line_array, line)
    line_sum = line_array.sum()
    '''方法1：
    cv.line(img, (x[0],x[1]), (y[0],y[1]), (255, 0, 0), 1)
    cv.line(img, (y[0],y[1]), (w[0],w[1]), (255, 0, 0), 1)
    cv.line(img, (w[0],w[1]), (h[0],h[1]), (255, 0, 0), 1)
    cv.line(img, (h[0],h[1]), (x[0],x[1]), (255, 0, 0), 1)
    或者
    cv.line(img, tuple(x), tuple(y), (255, 0, 0), 1)
    cv.line(img, tuple(y), tuple(w), (255, 0, 0), 1)
    cv.line(img, tuple(w), tuple(h), (255, 0, 0), 1)
    cv.line(img, tuple(h), tuple(x), (255, 0, 0), 1)
    待绘制的图像,string&待绘制的文字,文本框的左上角,文字类型，尺寸因子:值越大文字越大,字体颜色
    cv.putText(img, str(count), (w[0], w[1]), cv.FONT_HERSHEY_PLAIN, 0.5, (0, 255, 0))'''
    '''方法二：'''
    '''确定轮廓线精度'''
    epsilon = 0.0001*cv.arcLength(c,True)
    '''approxcurve二维矩阵'''
    approxcurve = cv.approxPolyDP(c,epsilon,True,)
    cv.polylines(img,[approxcurve],True,(255,0,0),1)
    print(type(approxcurve))
    print(approxcurve[:])
    curve1 = approxcurve[0,0,0]
    curve2 = approxcurve[0,0,1]
    cv.putText(img, str(count), (curve1,curve2), cv.FONT_HERSHEY_PLAIN, 0.5, (0, 255, 0))
    if miniarea < 8:
        continue
    count = count + 1
    area_array = np.append(area_array, miniarea)
    perimeter_array = np.append(perimeter_array,perimeter)
    '''求总面积和总周长'''
    area_sum = area_array.sum()
    perimeter_sum = perimeter_array.sum()
    '''round：浮点数取小数点后2位'''
    print('number',i,'的面积:',round(miniarea,2),'number',i,'的周长:',round(perimeter,2),'长度:',round(line,2))
print('总面积：', round(area_sum,2))
print('总周长：', round(perimeter_sum,2))
print('总长度:',round(line_sum,2))
print('米粒数量：',count)
'''std:标准差，mean均值，var方差'''
average_area = area_array.mean()
std_area = area_array.std()
var_area = area_array.var()
print('平均面积:',round(average_area,2))
print('面积标准差:',round(std_area,2))
print('面积方差:',round(var_area,2))
average_line = line_array.mean()
std_line = line_array.std()
var_line = line_array.var()
print('平均长度:',round(average_line,2))
print('长度标准差:',round(std_line,2))
print('长度方差:',round(var_line,2))
'''σ代表标准差，μ代表均值x=μ即为图像的对称轴,μ-3σ，μ+3σ为6σ'''
area1 = average_area - std_area*1.5
area2 = average_area + std_area*1.5
line1 = average_line - std_line*1.5
line2 = average_line + std_line*1.5
count1 = 0
count2 = 0
for miniarea in area_array:
    if miniarea > area1 and miniarea < area2:
        count1 = count1+1
for line in line_array:
    if line > line1 and line < line2:
        count2 = count2+1
print("面积3sigma的取值范围:", round(area1, 3), "~", round(area2, 3),'面积3sigma的数量:',count1)
print("长度3sigma的取值范围:", round(line1, 3), "~", round(line2, 3),'长度3sigma的数量:',count2)
cv.imshow('last',img)
cv.imshow('adaptivethreshold',opening)
cv.imwrite('last.jpg', img)
cv.waitKey()
cv.destroyAllWindows()